// Ball.cpp

// Implementacia objektu sveta - lopty

#include "Player/World/Ball.h"
#include "Player/World/World.h"


// Konstruktor
Ball::Ball(World* w) : Movable(w)
{
	valid = false;
	lastSeenTime = -2;
}

// Kopirovaci konstruktor
Ball::Ball(const Ball& ball) : Movable(ball)
{
	valid = ball.valid;
	lastSeenPos = ball.lastSeenPos;
	lastSeenTime = ball.lastSeenTime;
}

// Destruktor
Ball::~Ball()
{

}

// Operator priradenia
Ball& Ball::operator =(const Ball& ball)
{
	if(&ball == this)
		return *this;

	// Toto je naco dobre?
	Movable::operator =(ball);

	valid			= ball.valid;
	lastSeenPos		= ball.lastSeenPos;
	lastSeenTime	= ball.lastSeenTime;

	return *this;
}

// Prepoveda stav lopty v dalsom kroku
void Ball::Step()
{
	pos = pos + vel;
	vel *= world->params->server->ball_decay;
	age++;
}

// Vypocita poziciu, rychlost, ... lopty
void Ball::Recalculate(const SENSE_BODY* sb, const VISUAL_INFO* vi)
{		
	// Takto sa pozeram
	Angle viewDir = world->me->GetAbsDir() + world->me->GetNeckDir();
	
	// Vidim loptu a poznam jej vzdialenost a smer, vypocitam jej absolutnu poziciu
	Angle angle = viewDir + DegAngle(vi->ball.dir);
	pos = world->me->pos + PolarVector(vi->ball.dist, angle);

	WORLD_RECALC_DBG("  ball: viewDir: %f, dir: %f", viewDir.GetDeg(), vi->ball.dir);

	// Vidim aj jej rychlost?
	if(vi->ball.changesValid)
	{
		// (Predchodcovia to prebrali od TsinghuAeolus2002)
		Vector rpos = PolarVector(vi->ball.dist, DegAngle(vi->ball.dir));
		rpos /= rpos.GetLength();

		Vector rvel = RectVector(
			vi->ball.distChange * rpos.GetX() - vi->ball.dirChange * M_PI / 180.f * vi->ball.dist * rpos.GetY(),
			vi->ball.distChange * rpos.GetY() + vi->ball.dirChange * M_PI / 180.f * vi->ball.dist * rpos.GetX()
		);
			
		// Rotuj rvel
		rvel += viewDir;
		vel = world->me->vel + rvel;

//		vel = world->me->vel + PolarVector(vi->ball.distChange, angle) + PolarVector(vi->ball.dist * dirCh, angle).OrthoLeft();

		WORLD_RECALC_DBG("  ball: changesValid, pos: (%f, %f), vel: (%f, %f)", pos.GetX(), pos.GetY(), vel.GetX(), vel.GetY());
	}
	else
	{
		// Nevidim rychlost lopty, pouzije sa CMU metoda
		if((vi->ball.dist <= world->params->server->visible_distance) &&
			(world->state->GetSimTime() == lastSeenTime + 1) &&
			(world->state->GetSimTime() == world->me->GetLastSeenTime() + 1))
		{
			Vector correction = world->me->vel / world->me->type->player_decay - (world->me->pos - world->me->GetLastSeenPos());
				
			vel = (pos - lastSeenPos + correction);
			vel *= world->params->server->ball_decay;
		}

		// Pri kolizii, vynasobi sa rychlost lopty konstantou (-0.1)
		bool ballCollision = false;
		if(vi->ball.dist <= world->me->type->player_size + world->params->server->ball_size + 0.05)
		{
			ballCollision = true;
		}

		if(ballCollision && (world->state->GetSimTime() > lastSeenTime))
			vel *= -0.1f;

		WORLD_RECALC_DBG("  ball: CMU method, pos: (%f, %f), vel: (%f, %f)", pos.GetX(), pos.GetY(), vel.GetX(), vel.GetY());
	}

	// Prave teraz vidim loptu
	age = 0;
	lastSeenPos = pos;
	lastSeenTime = world->state->GetSimTime();
	valid = true;
}


